package com.ruoyi.common.utils.http;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.ruoyi.common.utils.StringUtils;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class KuJiaLeHttpUtil {
    private static final Logger log = LoggerFactory.getLogger(KuJiaLeHttpUtil.class);
    private static final String APP_KEY = "PbBUAqof3u";
    private static final String SECRET_KEY = "ScMLUxDPLU05S3fghEZxd1CNJlsikmAp";

    /**
     * 发送GET请求
     *
     * @param url 请求URL
     * @return 解析后的响应对象
     */
    public static ApiResponse get(String url) {
        return get(url, new HashMap<>());
    }

    /**
     * 发送带参数的GET请求
     *
     * @param url    请求URL
     * @param params 请求参数
     * @return 解析后的响应对象
     */
    public static ApiResponse get(String url, Map<String, Object> params) {
        try {
            // 构建带公有参数的URL
            String fullUrl = buildUrlWithParams(url, params);

            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            // 设置请求方法
            connection.setRequestMethod("GET");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));

            // 获取响应
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                return parseResponse(responseBody);
            } else {
                return new ApiResponse(String.valueOf(responseCode), "HTTP请求失败", null);
            }
        } catch (Exception e) {
            return new ApiResponse("-1", "请求发生异常: " + e.getMessage(), null);
        }
    }

    /**
     * 发送POST请求
     *
     * @param url 请求URL
     * @return 解析后的响应对象
     */
    public static ApiResponse post(String url) {
        return post(url, new HashMap<>(), "");
    }

    /**
     * 发送带参数的GET请求（支持泛型返回）
     *
     * @param url      请求URL
     * @param params   请求参数
     * @param dataType 返回数据类型
     * @return 带泛型的响应对象
     */
    public static <T> ApiResponse<T> get(String url, Map<String, Object> params, Class<T> dataType) {
        try {
            String fullUrl = buildUrlWithParams(url, params);
            log.debug("发送GET请求（泛型）：{}", fullUrl);

            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            connection.setRequestMethod("GET");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                return parseGenericResponse(responseBody, dataType);
            } else {
                return new ApiResponse<>(String.valueOf(responseCode), "HTTP请求失败", null);
            }
        } catch (Exception e) {
            log.error("GET请求（泛型）异常", e);
            return new ApiResponse<>("-1", "请求发生异常: " + e.getMessage(), null);
        }
    }


    /**
     * 发送带参数的GET请求（支持泛型返回）
     *
     * @param url      请求URL
     * @param params   请求参数
     * @param dataType 返回数据类型
     * @return 带泛型的响应对象
     */
    public static <T> ApiResponse<T> get(String url, Map<String, Object> params, TypeReference<T> dataType) {
        try {
            String fullUrl = buildUrlWithParams(url, params);
            log.debug("发送GET请求（泛型）：{}", fullUrl);

            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            connection.setRequestMethod("GET");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                return parseGenericResponse(responseBody, dataType);
            } else {
                return new ApiResponse<>(String.valueOf(responseCode), "HTTP请求失败", null);
            }
        } catch (Exception e) {
            log.error("GET请求（泛型）异常", e);
            return new ApiResponse<>("-1", "请求发生异常: " + e.getMessage(), null);
        }
    }

    /**
     * 发送带参数的GET请求可选是否需要拼接uid签名
     *
     * @param url      请求URL
     * @param params   请求参数
     * @param dataType 返回数据类型
     * @return 带泛型的响应对象
     */
    public static <T> ApiResponse<T> get(String url, Map<String, Object> params, boolean signIsUid, TypeReference<T> dataType) {
        try {
            String fullUrl = buildUrlWithParams(url, params, signIsUid);
            log.debug("发送GET请求（泛型）：{}", fullUrl);

            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            connection.setRequestMethod("GET");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                return parseGenericResponse(responseBody, dataType);
            } else {
                return new ApiResponse<>(String.valueOf(responseCode), "HTTP请求失败", null);
            }
        } catch (Exception e) {
            log.error("GET请求（泛型）异常", e);
            return new ApiResponse<>("-1", "请求发生异常: " + e.getMessage(), null);
        }
    }


    /**
     * 直接返回结果无错误码与msg
     *
     * @param url      请求URL
     * @param params   请求参数
     * @param dataType 返回数据类型
     * @return 带泛型的响应对象
     */
    public static <T> T getAllResult(String url, Map<String, Object> params, TypeReference<T> dataType) {
        try {
            String fullUrl = buildUrlWithParams(url, params);
            log.debug("发送GET请求（泛型）：{}", fullUrl);

            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            connection.setRequestMethod("GET");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                // 转换数据为指定类型
                return convertData(responseBody, dataType);
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("GET请求（泛型）异常", e);
            return null;
        }
    }

    /**
     * 发送带参数的POST请求（支持泛型返回）
     *
     * @param url      请求URL
     * @param urlParam URL参数
     * @param postData POST请求体数据
     * @param dataType 返回数据类型
     * @return 带泛型的响应对象
     */
    public static <T> ApiResponse<T> post(String url, Map<String, Object> urlParam, String postData, Class<T> dataType) {
        try {
            String fullUrl = buildUrlWithParams(url, urlParam);
            log.debug("发送POST请求（泛型）：{}", fullUrl);

            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            connection.setRequestMethod("POST");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");

            if (StringUtils.isNotBlank(postData)) {
                log.debug("POST请求数据（泛型）：{}", postData);
                try (DataOutputStream out = new DataOutputStream(connection.getOutputStream())) {
                    out.write(postData.getBytes(StandardCharsets.UTF_8));
                    out.flush();
                }
            }

            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                return parseGenericResponse(responseBody, dataType);
            } else {
                return new ApiResponse<>(String.valueOf(responseCode), "HTTP请求失败", null);
            }
        } catch (Exception e) {
            log.error("POST请求（泛型）异常", e);
            return new ApiResponse<>("-1", "请求发生异常: " + e.getMessage(), null);
        }
    }

    /**
     * 发送带参数的POST请求
     *
     * @param url      请求URL
     * @param urlParam 参数
     * @return 解析后的响应对象
     */
    public static ApiResponse post(String url, Map<String, Object> urlParam, String postData) {
        try {
            // 构建带公有参数的URL
            String fullUrl = buildUrlWithParams(url, urlParam);
            URL requestUrl = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            // 设置请求方法和头信息
            connection.setRequestMethod("POST");
            connection.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setReadTimeout((int) TimeUnit.SECONDS.toMillis(10));
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");

            // 写入POST参数
            if (StringUtils.isNotBlank(postData)) {
//                String postData = buildParamsString(params);
                try (DataOutputStream out = new DataOutputStream(connection.getOutputStream())) {
                    out.write(postData.getBytes(StandardCharsets.UTF_8));
                    out.flush();
                }
            }

            // 获取响应
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String responseBody = readInputStream(connection.getInputStream());
                return parseResponse(responseBody);
            } else {
                return new ApiResponse(String.valueOf(responseCode), "HTTP请求失败", null);
            }
        } catch (Exception e) {
            return new ApiResponse("-1", "请求发生异常: " + e.getMessage(), null);
        }
    }

    /**
     * 构建包含公有参数的完整URL
     *
     * @param url
     * @param params
     * @param signIsUid
     * @return
     */
    private static String buildUrlWithParams(String url, Map<String, Object> params, boolean signIsUid) {

        if (signIsUid) {
            return buildUrlWithParams(url, params);
        }

        try {
            // 创建包含所有参数的Map（私有参数 + 公有参数）
            Map<String, Object> allParams = new HashMap<>();
            if (params != null) {
                allParams.putAll(params);
            }

            long now = System.currentTimeMillis();
            // 添加公有参数
            allParams.put("appkey", APP_KEY);
            allParams.put("timestamp", String.valueOf(now));
            String sign;
            // 生成签名
            sign = md5(SECRET_KEY + APP_KEY + now);
            allParams.put("sign", sign);

            // 构建参数字符串
            String paramsString = buildParamsString(allParams);

            // 拼接URL
            if (url.contains("?")) {
                return url + "&" + paramsString;
            } else {
                return url + "?" + paramsString;
            }
        } catch (Exception e) {
            throw new RuntimeException("构建URL失败", e);
        }
    }

    /**
     * 构建包含公有参数的完整URL
     */
    private static String buildUrlWithParams(String url, Map<String, Object> params) {
        try {
            // 创建包含所有参数的Map（私有参数 + 公有参数）
            Map<String, Object> allParams = new HashMap<>();
            String appuid = null;
            if (params != null) {
                allParams.putAll(params);
                if (params.containsKey("appuid")) {
                    appuid = params.get("appuid").toString();
                }
            }

            long now = System.currentTimeMillis();
            // 添加公有参数
            allParams.put("appkey", APP_KEY);
            allParams.put("timestamp", String.valueOf(now));
            String sign;
            // 生成签名
            if (StringUtils.isNotNull(appuid)) {
                sign = md5(SECRET_KEY + APP_KEY + appuid + now);
            } else {
                sign = md5(SECRET_KEY + APP_KEY + now);
            }
            allParams.put("sign", sign);

            // 构建参数字符串
            String paramsString = buildParamsString(allParams);

            // 拼接URL
            if (url.contains("?")) {
                return url + "&" + paramsString;
            } else {
                return url + "?" + paramsString;
            }
        } catch (Exception e) {
            throw new RuntimeException("构建URL失败", e);
        }
    }


    /**
     * 构建参数字符串
     */
    private static String buildParamsString(Map<String, Object> params) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name())).append("=").append(URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8.name()));
        }
        return sb.toString();
    }

    /**
     * 读取输入流
     */
    private static String readInputStream(InputStream inputStream) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        reader.close();
        return sb.toString();
    }

    /**
     * 解析响应数据
     */
    private static ApiResponse parseResponse(String responseBody) {
        try {
            JSONObject json = JSONObject.parseObject(responseBody);
            String code = json.getString("c");
            String message = json.getString("m");
            String dataStr = json.getString("d");
            try {
                JSONObject data = JSONObject.parse(dataStr);
                return new ApiResponse(code, message, data);
            } catch (Exception e) {

            }

            return new ApiResponse(code, message, dataStr);
        } catch (Exception e) {
            return new ApiResponse("-2", "解析响应失败: " + e.getMessage(), null);
        }
    }

    /**
     * 响应结果封装类
     */
    @Getter
    public static class ApiResponse<M> {
        // Getters
        private String code;
        private String message;
        private M data;

        public ApiResponse(String code, String message, M data) {
            this.code = code;
            this.message = message;
            this.data = data;
        }

        // 判断请求是否成功
        public boolean isSuccess() {
            return "0".equals(code);
        }
    }


    /**
     * 解析泛型响应数据
     */
    private static <T> ApiResponse<T> parseGenericResponse(String responseBody, Class<T> dataType) {
        try {
            JSONObject json = JSONObject.parseObject(responseBody);
            String code = json.getString("c");
            String message = json.getString("m");
            String dataStr = json.getString("d");

            // 转换数据为指定类型
            T data = convertData(dataStr, dataType);
            return new ApiResponse<>(code, message, data);
        } catch (Exception e) {
            log.error("解析泛型响应失败", e);
            return new ApiResponse<>("-2", "解析响应失败: " + e.getMessage(), null);
        }
    }

    /**
     * 解析泛型响应数据
     */
    private static <T> ApiResponse<T> parseGenericResponse(String responseBody, TypeReference<T> dataType) {
        try {
            JSONObject json = JSONObject.parseObject(responseBody);
            String code = json.getString("c");
            String message = json.getString("m");
            String dataStr = json.getString("d");

            // 转换数据为指定类型
            T data = convertData(dataStr, dataType);
            return new ApiResponse<>(code, message, data);
        } catch (Exception e) {
            log.error("解析泛型响应失败", e);
            return new ApiResponse<>("-2", "解析响应失败: " + e.getMessage(), null);
        }
    }

    /**
     * 将字符串转换为指定类型
     */
    private static <T> T convertData(String dataStr, Class<T> dataType) {
        if (dataStr == null || dataType == null) {
            return null;
        }

        // 字符串类型直接返回
        if (dataType == String.class) {
            return dataType.cast(dataStr);
        }

        // 尝试解析为指定类型
        try {
            return JSON.parseObject(dataStr, dataType);
        } catch (Exception e) {
            log.warn("无法将数据解析为类型: {}", dataType.getName(), e);
            return null;
        }
    }

    /**
     * 将字符串转换为指定类型
     */
    private static <T> T convertData(String dataStr, TypeReference<T> dataType) {
        if (dataStr == null || dataType == null) {
            return null;
        }
        // 尝试解析为指定类型
        try {
            return JSON.parseObject(dataStr, dataType);
        } catch (Exception e) {
            log.warn("无法将数据解析为类型", e);
            return null;
        }
    }


    private static String md5(String str) {
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            byte[] bytes = str.getBytes();
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(bytes);
            byte[] updateBytes = messageDigest.digest();
            int len = updateBytes.length;
            char myChar[] = new char[len * 2];
            int k = 0;
            for (int i = 0; i < len; i++) {
                byte byte0 = updateBytes[i];
                myChar[k++] = hexDigits[byte0 >>> 4 & 0x0f];
                myChar[k++] = hexDigits[byte0 & 0x0f];
            }
            return new String(myChar);
        } catch (Exception e) {
            return null;
        }
    }
}
